home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
shells
/
bashsrc.zoo
/
jobs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-05
|
41KB
|
1,722 lines
/* The thing that makes children, remembers them, and contains wait loops. */
/* Copyright (C) 1989 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Something that can be ignored. */
#define IGNORE_ARG (char *)0
#include "config.h"
#ifndef JOB_CONTROL
#include "nojobs.c"
#else
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/param.h>
/* Terminal handling stuff, to save and restore tty state. */
#define NEW_TTY_DRIVER
#if defined(SYSV) || defined(hpux) || defined(ALTOS)
#undef NEW_TTY_DRIVER
#endif /* SYSV || hpux || ALTOS */
#ifdef NEW_TTY_DRIVER
#include <sgtty.h>
#else
#include <termio.h>
#endif /* NEW_TTY_DRIVER */
/* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */
#ifdef hpux
#include <bsdtty.h>
#endif /* hpux */
#include "shell.h"
#include "jobs.h"
/* Not all systems define errno in errno.h. */
extern int errno;
#ifndef sigmask
#define sigmask(x) (1 << ((x)-1))
#endif
#ifndef SIGABRT
#define SIGABRT SIGIOT
#endif
#ifndef SIGCHLD
#define SIGCHLD SIGCLD
#endif
/* The array of known jobs. */
JOB **jobs = (JOB **)NULL;
/* The number of slots currently allocated to JOBS. */
int job_slots = 0;
/* The number of additional slots to allocate when we run out. */
#define JOB_SLOTS 5
/* The controlling tty for this shell. */
int shell_tty;
/* The shell's process group. */
int shell_pgrp = -1;
/* The terminal's process group. */
int terminal_pgrp = -1;
/* The process group of the shell's parent. */
int original_pgrp = -1;
/* The process group of the pipeline currently being made. */
int pipeline_pgrp = 0;
/* The job which is current; i.e. the one that `%+' stands for. */
int current_job = NO_JOB;
/* The previous job; i.e. the one that `%-' stands for. */
int previous_job = NO_JOB;
/* Last child made by the shell. */
int last_made_pid = -1;
/* Pid of the last asynchronous child. */
int last_asynchronous_pid = -1;
/* Non-zero allows asynchronous job notification. If not set,
then job state notification only takes place just before a
prompt is printed. */
int asynchronous_notification = 0;
#ifndef hpux
/* The total amount of system time spent running processes for me. */
struct timeval total_systime = {0, 0};
long system_minutes_used = 0;
int system_seconds_used = 0;
/* The total amount of user time spent running processes for me. */
struct timeval total_usertime = {0, 0};
long user_minutes_used = 0;
int user_seconds_used = 0;
#endif /* hpux */
/* The pipeline currently being built. */
PROCESS *the_pipeline = (PROCESS *)NULL;
/* If this is non-zero, do job control. */
int job_control = 1;
/* Call this when you start making children. */
int already_making_children = 0;
/* These are definitions to map POSIX 1003.1 functions onto existing BSD
library functions and system calls. */
#define setpgid(pid, pgrp) setpgrp (pid, pgrp)
#define tcsetpgrp(fd, pgrp) ioctl ((fd), TIOCSPGRP, &(pgrp))
tcgetpgrp (fd)
int fd;
{
int pgrp;
/* ioctl will handle setting errno correctly. */
if (ioctl (fd, TIOCGPGRP, &pgrp) < 0)
return (-1);
return (pgrp);
}
/* END of POISX 1003.1 definitions. */
making_children ()
{
if (already_making_children)
return;
already_making_children = 1;
start_pipeline ();
}
stop_making_children ()
{
already_making_children = 0;
}
/* Start building a pipeline. */
start_pipeline ()
{
if (the_pipeline)
{
discard_pipeline (the_pipeline);
the_pipeline = (PROCESS *)NULL;
pipeline_pgrp = 0;
}
}
/* Stop building a pipeline. Install the process list in the job array.
This returns the index of the newly installed job.
DEFERRED is a command structure to be executed upon satisfactory
execution exit of this pipeline. */
int
stop_pipeline (async, deferred)
int async;
COMMAND *deferred;
{
register int i, j;
int oldmask;
JOB *newjob = (JOB *)NULL;
char *get_string_value ();
oldmask = sigblock (sigmask (SIGCHLD));
cleanup_dead_jobs ();
if (!job_slots)
{
jobs =
(JOB **)xmalloc ((1 + (job_slots = JOB_SLOTS)) * sizeof (JOB *));
/* Now blank out these new entries. */
for (i = 0; i < job_slots; i++)
jobs[i] = (JOB *)NULL;
}
/* Scan from the last slot backward, looking for the next free one. */
for (i = job_slots; i; i--)
if (jobs[i - 1])
break;
/* Do we need more room? */
if (i == job_slots)
{
jobs = (JOB **)realloc
(jobs, (1 + (job_slots += JOB_SLOTS)) * sizeof (JOB *));
for (j = i; j < job_slots; j++)
jobs[j] = (JOB *)NULL;
}
/* Add the current pipeline to the job list. */
if (the_pipeline)
{
extern int errno, sys_nerr;
extern char *sys_errlist[];
register PROCESS *p;
newjob = (JOB *)xmalloc (sizeof (JOB));
for (p = the_pipeline; p->next != the_pipeline; p = p->next);
p->next = (PROCESS *)NULL;
newjob->pipe = (PROCESS *)reverse_list (the_pipeline);
for (p = newjob->pipe; p->next; p = p->next);
p->next = newjob->pipe;
the_pipeline = (PROCESS *)NULL;
newjob->pgrp = pipeline_pgrp;
pipeline_pgrp = 0;
/* Flag to see if in another pgrp. */
newjob->job_control = job_control;
/* Set the state of this pipeline. */
{
register PROCESS *p = newjob->pipe;
register int any_alive = 0;
register int any_stopped = 0;
do
{
any_alive |= p->running;
any_stopped |= WIFSTOPPED (p->status);
p = p->next;
}
while (p != newjob->pipe);
if (any_alive)
{
newjob->state = JRUNNING;
}
else
{
if (any_stopped)
newjob->state = JSTOPPED;
else
newjob->state = JDEAD;
}
}
newjob->notified = 0;
newjob->wd = get_string_value ("PWD");
if (newjob->wd)
newjob->wd = savestring (newjob->wd);
else
newjob->wd = (char *)get_working_directory ("");
if (!(newjob->wd))
newjob->wd = savestring ("<no directory>");
newjob->deferred = deferred;
jobs[i] = newjob;
}
if (async)
{
if (newjob)
newjob->foreground = 0;
reset_current ();
}
else
{
if (newjob)
{
newjob->foreground = 1;
/*
* !!!!! NOTE !!!!! (chet@ins.cwru.edu)
*
* The currently-accepted job control wisdom says to set the
* terminal's process group n+1 times in an n-step pipeline:
* once in the parent and once in each child. This is where
* the parent gives it away.
*
*/
if (job_control && pipeline_pgrp)
give_terminal_to (pipeline_pgrp);
}
}
stop_making_children ();
sigsetmask (oldmask);
return (current_job);
}
/* Delete all DEAD jobs that the user had received notification about. */
cleanup_dead_jobs ()
{
int oldmask = sigblock (sigmask (SIGCHLD));
register int i;
for (i = 0; i < job_slots; i++)
if (jobs[i] && JOBSTATE (i) == JDEAD && jobs[i]->notified)
delete_job (i);
sigsetmask (oldmask);
}
/* Delete the job at INDEX from the job list. */
delete_job (index)
int index;
{
register JOB *temp = jobs[ind